package com.lzp.customview.togglebtn

import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.RectF
import android.os.Build
import android.util.AttributeSet
import android.view.Gravity
import android.view.MotionEvent
import android.view.View
import android.widget.FrameLayout
import android.widget.TextView
import androidx.annotation.ColorInt
import androidx.customview.widget.ViewDragHelper
import com.utils.SizeUtils
import com.view.ViewHelper
import kotlin.math.pow

/**
 * @describe:
 * @Author: lixiaopeng
 * @Date: 1/22/21
 */
class SegmentedSeekBar : FrameLayout {

    private val TAG = "SegmentedSeekBar"
    private val dp1 = SizeUtils.dip2px(context, 1f)

    private val viewHeight = dp1 * 68

    private var startProgress = 0f
    private var endProgress = 100f

    //精度 - 保留小数点后几位，默认不保留
    private var precision = 0

    private var textSize = 15f

    private val seekBarTopMargin = dp1 * 36

    private var startAndEndTextColor = 0xff7c828c.toInt()
    private val startTextView = TextView(context)
    private val endTextView = TextView(context)

    private var leftAndRightTextColor = 0xff2c2d2e.toInt()
    private val leftTextView = TextView(context)

    private var leftProgress = 30f
    private var deltaProgress = 20f

    private val rightTextView = TextView(context)

    private var lineHeight = dp1 * 2
    private var lineColor = 0xffcfd7e2.toInt()
    private val linePaint = Paint(Paint.ANTI_ALIAS_FLAG or Paint.DITHER_FLAG)

    private val seekBarView = SeekBarView(context)
    private val seekBarViewHeight = dp1 * 28

    private val shaderColor = 0x30000000.toInt()

    private var progressWidth = 0f

    private var leftX = 0

    //阴影高度
    private val elevationHeight = dp1 * 2

    private var progressChangedListener: OnProgressChangedListener? = null

    private val dragHelper: ViewDragHelper = ViewDragHelper.create(this, DragHelperCallBack())

    constructor(context: Context) : this(context, null)
    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
        initView()
    }

    fun setStartAndEndProgress(startProgress: Float, endProgress: Float) {
        this.startProgress = startProgress
        this.endProgress = endProgress
    }

    fun getLeftProgress(): String {
        return precisionProgressStr(leftProgress)
    }

    fun getRightProgress(): String {
        return precisionProgressStr(leftProgress + deltaProgress)
    }

    fun setLeftProgress(leftProgress: Float) {
        this.leftProgress = leftProgress
    }

    fun setLeftAndDeltaProgress(leftProgress: Float, deltaProgress: Float) {
        this.leftProgress = leftProgress
        this.deltaProgress = deltaProgress
    }

    fun refresh() {
        startTextView.text = precisionProgressStr(startProgress)
        endTextView.text = precisionProgressStr(endProgress)
        leftX = computeProgressX(leftProgress).toInt()
        freshSeekBar()
        updateText()
    }

    fun setLineColor(@ColorInt lineColor: Int) {
        this.lineColor = lineColor
        linePaint.color = lineColor
    }

    inner class DragHelperCallBack : ViewDragHelper.Callback() {
        override fun tryCaptureView(child: View, pointerId: Int): Boolean {
            return child == seekBarView
        }

        override fun clampViewPositionHorizontal(child: View, left: Int, dx: Int): Int {
            var tempLeft = left
            if (left < 0) {
                tempLeft = 0
            } else if (left > width - child.width) {
                tempLeft = width - child.width
            }
            leftX = tempLeft

            val temProgress = leftProgress
            x2Progress(leftX.toFloat())
            updateText()
            if (leftProgress != temProgress) {
                progressChangedListener?.onProgressChanged()
            }
            return tempLeft
        }

        override fun clampViewPositionVertical(child: View, top: Int, dy: Int): Int {
            return seekBarTopMargin.toInt()
        }

        override fun onViewReleased(releasedChild: View, xvel: Float, yvel: Float) {
            //停止滚动之后
        }
    }

    private fun initView() {
        startTextView.setTextColor(startAndEndTextColor)
        startTextView.textSize = textSize
        startTextView.text = precisionProgressStr(startProgress)
        startTextView.layoutParams = LayoutParams(LayoutParams.WRAP_CONTENT, dp1.toInt() * 23)
        addView(startTextView)

        endTextView.setTextColor(startAndEndTextColor)
        endTextView.textSize = textSize
        endTextView.text = precisionProgressStr(endProgress)
        val layoutParams = LayoutParams(LayoutParams.WRAP_CONTENT, dp1.toInt() * 23)
        layoutParams.gravity = Gravity.RIGHT
        endTextView.layoutParams = layoutParams
        addView(endTextView)

        leftTextView.paint.isFakeBoldText = true
        leftTextView.setTextColor(leftAndRightTextColor)
        leftTextView.textSize = textSize
        leftTextView.text = precisionProgressStr(leftProgress)
        //宽度写大一点，免得每次文字修改都测量
        leftTextView.layoutParams = LayoutParams(300, dp1.toInt() * 23)
        leftTextView.gravity = Gravity.CENTER_HORIZONTAL
        addView(leftTextView)

        rightTextView.paint.isFakeBoldText = true
        rightTextView.setTextColor(leftAndRightTextColor)
        rightTextView.textSize = textSize
        rightTextView.text = precisionProgressStr(leftProgress + deltaProgress)
        //宽度写大一点，免得每次文字修改都测量
        rightTextView.layoutParams = LayoutParams(300, dp1.toInt() * 23)
        rightTextView.gravity = Gravity.CENTER_HORIZONTAL
        addView(rightTextView)

        val seekBarViewLayout = LayoutParams(dp1.toInt() * 95, seekBarViewHeight.toInt())
        seekBarViewLayout.topMargin = seekBarTopMargin.toInt()
        seekBarViewLayout.bottomMargin = dp1.toInt() * 4
        seekBarViewLayout.leftMargin = leftX
        seekBarView.layoutParams = seekBarViewLayout
        //需要阴影打开注释
       /* seekBarView.elevation = elevationHeight
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            seekBarView.outlineSpotShadowColor = shaderColor
        }*/
        addView(seekBarView)
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        progressWidth = MeasureSpec.getSize(widthMeasureSpec).toFloat() - dp1 * 2
        setMeasuredDimension(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getMode(widthMeasureSpec)), MeasureSpec.makeMeasureSpec(viewHeight.toInt(), MeasureSpec.EXACTLY))
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        if (w != 0) {
            leftX = computeProgressX(leftProgress).toInt()
            freshSeekBar()
            updateText()
        }
    }

    private fun freshSeekBar() {
        post {
            val seekBarViewLayout = seekBarView.layoutParams as LayoutParams
            seekBarViewLayout.width = getSeekBarWidth(deltaProgress).toInt()

            seekBarViewLayout.leftMargin = leftX
            seekBarView.layoutParams = seekBarViewLayout
        }
    }

    private fun updateText() {
        leftTextView.text = precisionProgressStr(leftProgress)
        rightTextView.text = precisionProgressStr(leftProgress + deltaProgress)
        post {
            leftTextView.translationX = leftX.toFloat() - leftTextView.width / 2
            rightTextView.translationX = leftX.toFloat() + getSeekBarWidth(deltaProgress) - rightTextView.width / 2
        }
    }

    /**
     * 坐标转进度
     */
    private fun x2Progress(x: Float) {
        val xRate = x / progressWidth
        val totalProgress = endProgress - startProgress
        var tempProgress = startProgress + totalProgress * xRate
        if (tempProgress < startProgress) {
            tempProgress = startProgress
        }
        if (tempProgress + deltaProgress > endProgress) {
            tempProgress = endProgress - deltaProgress
        }
        leftProgress = tempProgress
    }

    /**
     * 进度转坐标
     */
    private fun computeProgressX(progress: Float): Float {
        val totalProgress = endProgress - startProgress
        val dProgressX = progressWidth / totalProgress
        return (progress - startProgress) * dProgressX
    }

    private fun getSeekBarWidth(deltaProgress: Float): Float {
        val totalProgress = endProgress - startProgress
        val dProgressX = progressWidth / totalProgress
        return deltaProgress * dProgressX
    }

    /**
     * 进度按精度转进度
     */
    private fun precisionProgressStr(progress: Float): String {
        if (precision == 0) {
            return progress.toInt().toString()
        }
        //double和float相乘会丢失精度
        val pow = 10.toDouble().pow(precision.toDouble()).toFloat()
        var tempProgress = (progress * pow).toInt() / pow.toFloat()
        if (tempProgress > endProgress) {
            tempProgress = endProgress
        }
        if (tempProgress < startProgress) {
            tempProgress = startProgress
        }
        return tempProgress.toString()
    }

    init {
        linePaint.style = Paint.Style.STROKE
        linePaint.strokeWidth = lineHeight
        linePaint.strokeCap = Paint.Cap.ROUND
        linePaint.color = lineColor
    }

    override fun dispatchDraw(canvas: Canvas?) {
        canvas?.let {
            it.drawLine(dp1.toFloat(),
                    seekBarTopMargin + (seekBarViewHeight - lineHeight) / 2f,
                    progressWidth + dp1,
                    seekBarTopMargin + (seekBarViewHeight - lineHeight) / 2f,
                    linePaint)
        }
        super.dispatchDraw(canvas)
    }


    override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
        return if (ev != null) {
            dragHelper.shouldInterceptTouchEvent(ev)
        } else {
            super.onInterceptTouchEvent(ev)
        }
    }

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        event?.let {
            dragHelper.processTouchEvent(event)
            return true
        }
        return super.onTouchEvent(event)
    }

    fun setOnProgressChangedListener(progressChangedListener: OnProgressChangedListener?) {
        this.progressChangedListener = progressChangedListener
    }

    fun setLeftAndRightTextColor(color: Int) {
        leftTextView.setTextColor(color)
        rightTextView.setTextColor(color)
    }

    interface OnProgressChangedListener {
        fun onProgressChanged()
    }

    /**
     * 滑块view
     */
    private class SeekBarView : View {

        private val dp1 = SizeUtils.dip2px(context, 1)

        private val outLineWidth = dp1.toFloat()
        private val outLineColor = 0x19000000.toInt()

        private val inLinePaint = Paint(Paint.ANTI_ALIAS_FLAG or Paint.DITHER_FLAG)
        private val inLineColor = 0xe67c828c.toInt()
        private val inLineHeight = dp1 * 15
        private val inLineWidth = dp1 * 3
        private val inLineMargin = dp1 * 5
        private val inLineTotalWidth = inLineWidth * 3 + inLineMargin * 2


        constructor(context: Context?) : this(context, null)
        constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {
            background = ViewHelper.createShapeDrawable(dp1 * 4f, 0xffffffff.toInt(), outLineColor, outLineWidth)
        }

        init {
            inLinePaint.color = inLineColor
            inLinePaint.style = Paint.Style.STROKE
            inLinePaint.strokeWidth = inLineWidth.toFloat()
            inLinePaint.strokeCap = Paint.Cap.ROUND
        }

        override fun onDraw(canvas: Canvas?) {
            super.onDraw(canvas)
            canvas?.let {
                val startX = (measuredWidth - inLineTotalWidth) / 2f + inLineWidth / 2f
                val startY = (measuredHeight - inLineHeight) / 2f
                val endY = (measuredHeight - inLineHeight) / 2f + inLineHeight
                val dLine = inLineMargin + inLineWidth
                it.drawLine(startX, startY, startX, endY, inLinePaint)
                it.drawLine(startX + dLine, startY, startX + dLine, endY, inLinePaint)
                it.drawLine(startX + dLine * 2f, startY, startX + dLine * 2f, endY, inLinePaint)
            }
        }
    }

}